# new Vue 发生了什么
# 通过 new 实例化 Vue
- /src/core/instance/index.js
function Vue (options) {
if (process.env.NODE_ENV !== 'production' &&
!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options)
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# this._init()
- /src/core/instance/init.js
- 合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher 等。
- vm.$options = options
- vm.$mount 挂载 vm
export function initMixin (Vue: Class<Component>) {
Vue.prototype._init = function (options?: Object) {
const vm: Component = this
// a uid
vm._uid = uid++
let startTag, endTag
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
startTag = `vue-perf-start:${vm._uid}`
endTag = `vue-perf-end:${vm._uid}`
mark(startTag)
}
// a flag to avoid this being observed
vm._isVue = true
// merge options
// 是否子组件 非根组件 非 new Vue(options)
/*
new Vue({
el: '#app',
data() {
return ...
}
})
*/
if (options && options._isComponent) {
// optimize internal component instantiation
// since dynamic options merging is pretty slow, and none of the
// internal component options needs special treatment.
initInternalComponent(vm, options)
} else {
// 根组件
// 合并全局配置到根组件上
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
}
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
// 新增 vm._renderProxy
initProxy(vm)
} else {
vm._renderProxy = vm
}
// expose real self
vm._self = vm
// 初始化组件实例属性 $parent $children $refs $root
initLifecycle(vm)
// 注册组件上的事件
initEvents(vm)
// $slots $createElement
// 通过 defineReactive 添加 $attrs $listeners
initRender(vm)
// 执行生命周期 beforeCreate
callHook(vm, 'beforeCreate')
// 解析 inject 配置项 将配置项 key 添加到 vm 上 并做响应式处理
initInjections(vm) // resolve injections before data/props
// 处理 props data method watch computed
initState(vm)
// 将配置的 provide 添加到 vm
initProvide(vm) // resolve provide after data/props
// 调用生命周期 created 方法
callHook(vm, 'created')
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
vm._name = formatComponentName(vm, false)
mark(endTag)
measure(`vue ${vm._name} init`, startTag, endTag)
}
// 如果有 el 默认执行 $mount 挂载
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
← 从入口开始 Vue 实例挂载的实现 →